package org.bdware.doip.core.doipMessage;

import java.net.InetSocketAddress;

public class MessageEnvelope {

    public byte majorVersion;
    public byte minVersion;
    private short flag;
    public int reserved;
    public int requestId;
    public int sequenceNumber;  //&& -1 && resend = true means all packet has been received by client
    public int totalNumber;
    public int contentLength;

    //generate from flag
    private transient boolean isResend = false;
    private transient boolean isTruncated = false;
    private transient boolean isEncrypted = false;

    public transient byte[] content;
    public transient InetSocketAddress sender;

    public MessageEnvelope(){
        isResend = isTruncated = isEncrypted = false;
        flag = 0;
        sequenceNumber = 0;
        totalNumber = 1;
        reserved = 0;
        majorVersion = minVersion = 3;
    }

    public MessageEnvelope(short flag,int requestId, int sequenceNumber, int totalNumber){
        this.flag = flag;
        if(isResend0()) isResend = true;
        if(isTruncated0()) isTruncated = true;
        this.requestId = requestId;
        this.sequenceNumber = sequenceNumber;
        this.totalNumber = totalNumber;
        this.reserved = 0;
        majorVersion = minVersion = 3;
    }

    public static MessageEnvelope createResendMessage(int reqId, int order, InetSocketAddress sender) {
        MessageEnvelope msg = new MessageEnvelope((short)-0x8000,reqId,order,0);
        msg.requestId = reqId;
        msg.sequenceNumber = order;
        msg.contentLength = 0;
        msg.content = new byte[0];
        msg.setSender(sender);
        return msg;
    }

    public void setContent(byte[] content){
        this.content = content;
    }

    public boolean isResend(){
        return isResend;
    }

    public boolean isTruncated(){
        return isTruncated;
    }

    public boolean isEncrypted(){
        return isEncrypted;
    }

    private boolean isResend0(){
        return this.flag < 0;
    }

    private boolean isTruncated0(){
        return (short)(this.flag << 1 ) < 0 ;
    }
    private boolean isEncrypted0(){
        return (short)(this.flag << 2 ) < 0 ;
    }

    public void setFlag(Short flag){
        this.flag =flag;
        isResend = isResend0();
        isTruncated = isTruncated0();
        isEncrypted = isEncrypted0();
    }

    public short getFlag(){
        updateFlag();
        return flag;
    }

    public void setResend(boolean isResend){
        this.isResend = isResend;
    }

    public void setTruncated(boolean isTruncated){
        this.isTruncated = isTruncated;
    }

    public void setEncrypted(boolean isEncrypted){
        this.isEncrypted = isEncrypted;
    }


    private void updateFlag(){
        this.flag = 0;
        if(isResend) this.flag = (short) (this.flag | -0x8000);
        if(isTruncated) this.flag = (short)(this.flag | 0x4000);
        if(isEncrypted) this.flag = (short)(this.flag | 0x2000);
    }

    public void setSender(InetSocketAddress sender) {
        this.sender = sender;
    }
    public InetSocketAddress getSender() {
        return sender;
    }

}
